package com.niiwoo.civet.account.listener;

import com.alibaba.fastjson.JSON;
import com.google.common.util.concurrent.RateLimiter;
import com.niiwoo.civet.account.constant.MQConstant;
import com.niiwoo.civet.account.dto.request.ApplyWithholdRequestDTO;
import com.niiwoo.civet.account.service.local.trade.WithholdFacade;
import com.niiwoo.civet.account.service.local.trade.WithholdService;
import com.niiwoo.civet.trade.dto.response.WithholdResultDTO;
import com.niiwoo.tripod.provider.exception.BizException;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

import javax.annotation.PostConstruct;
import java.io.IOException;

/**
 * 代扣MQ消费
 * Created by xiaoyingping on 2018/4/25.
 */
@Component
@Slf4j
public class WithholdListener {

    @Autowired
    private WithholdFacade withholdFacade;
    @Autowired
    private WithholdService withholdService;

    @Value("${withholdRateLimiterCount}")
    private Double rateLimiterCount;

    //代扣令牌桶，允许每秒向存管发送rateLimiterCount次代扣请求
    private static RateLimiter rateLimiter;


    @PostConstruct
    public void init(){
        log.info("withholdRateLimiterCount is {}", rateLimiterCount);
        Assert.notNull(rateLimiterCount,"rateLimiterCount不能为空");
        rateLimiter = RateLimiter.create(rateLimiterCount);
    }

    /**
     * 监听申请代扣消息
     * @param message
     * @param channel
     * @throws IOException
     */
    @RabbitListener(queues = {MQConstant.WITHHOLD_APPLY_DATA_QUEUE})
    public void listenerWithdrawholdApply(Message message, Channel channel) throws IOException {
        String messageBody = new String(message.getBody(), "UTF-8");
        log.info("接收到代扣MQ消息:{}", messageBody);

        ApplyWithholdRequestDTO applyWithholdRequestDTO = JSON.parseObject(messageBody, ApplyWithholdRequestDTO.class);
        try {
            double acquireWaitTime = rateLimiter.acquire();
            log.info("获取代扣请求令牌，等待{}秒", acquireWaitTime);

            //申请代扣
            withholdFacade.applyWithhold(applyWithholdRequestDTO);
        } catch (BizException e) {
            log.error("消费代扣MQ消息发生业务异常:"+ messageBody,e);

            //发送异常结果通知MQ
            WithholdResultDTO withholdResultDTO = new WithholdResultDTO();
            withholdResultDTO.setOrderId(applyWithholdRequestDTO.getOrderId());
            withholdResultDTO.setCode(e.getErrorCode());
            withholdResultDTO.setMessage(e.getMessage());
            withholdService.sendWithholdResultNotifyMq(withholdResultDTO);
        } catch (Exception e) {
            log.error("消费代扣MQ消息发生系统异常:"+ messageBody,e);
        } finally {
            log.info("代扣MQ消息ACK:{}", messageBody);
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        }
    }
}
